// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SystemHotkey.cs" company="TechBits">
//   Copyright (c) TechBits. All rights reserved.
// </copyright>
// <summary>
//   Defines the SystemHotkey type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace IntelliShortCut.UI.Controls
{
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Windows.Forms;
    
    using Data;

    /// <summary>
    /// Handles a System Hotkey.
    /// </summary>
    public class SystemHotkey : Component, IDisposable
    {
        #region "Private Members"

        /// <summary>
        /// Components of the designer.
        /// </summary>
        private Container components;

        /// <summary>
        /// Window for WM_Hotkey Messages.
        /// </summary>
        private readonly DummyWindowWithEvent _window = new DummyWindowWithEvent();

        /// <summary>
        /// Stores the shortcut selected by the user.
        /// </summary>
        private Shortcut _hotKey = Shortcut.None;

        #endregion

        #region "Constructors"

        /// <summary>
        /// Initializes a new instance of the <see cref="SystemHotkey"/> class.
        /// </summary>
        /// <param name="container">
        /// The container.
        /// </param>
        public SystemHotkey(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
            _window.ProcessMessage += MessageEvent;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SystemHotkey"/> class.
        /// </summary>
        public SystemHotkey()
        {
            InitializeComponent();
            if (!DesignMode)
            {
                _window.ProcessMessage += MessageEvent;
            }
        }

        #endregion

        #region "Events"

        /// <summary>
        /// The shorcut has been preseed.
        /// </summary>
        public event EventHandler Pressed;

        /// <summary>
        /// An error has been ocurred.
        /// </summary>
        public event EventHandler Error;

        #endregion

        #region "Public Methods"

        /// <summary>
        /// Gets or sets a value indicating whether IsRegistered.
        /// </summary>
        public bool IsRegistered { get; set; }

        /// <summary>
        /// Gets or sets Shortcut.
        /// </summary>
        [DefaultValue(Shortcut.None)]
        public Shortcut Shortcut
        {
            get
            {
                return _hotKey;
            }

            set
            {
                // Don't register in Designmode
                if (DesignMode)
                {
                    _hotKey = value; 
                    return;
                }

                // Unregister previous registered Hotkey
                if (IsRegistered && _hotKey != value)
                {
                    if (UnregisterHotkey())
                    {
                        Debug.WriteLine("Unreg: OK");
                        IsRegistered = false;
                    }
                    else
                    {
                        if (Error != null)
                        {
                            Error(this, EventArgs.Empty);
                        }

                        Debug.WriteLine("Unreg: ERR");
                    }
                }

                if (value == Shortcut.None)
                {
                    _hotKey = value; 
                    return;
                }

                // Register new Hotkey
                if (RegisterHotkey(value))
                {
                    Debug.WriteLine("Reg: OK");
                    IsRegistered = true;
                }
                else
                {
                    if (Error != null)
                    {
                        Error(this, EventArgs.Empty);
                    }

                    Debug.WriteLine("Reg: ERR");
                }
                
                _hotKey = value;
            }
        }

        /// <summary>
        /// Overloads the Dispose method.
        /// </summary>
        public new void Dispose()
        {
            if (IsRegistered)
            {
                if (UnregisterHotkey())
                {
                    Debug.WriteLine("Unreg: OK");
                }
            }

            Debug.WriteLine("Disposed");
        }

        #endregion

        #region "Component Designer generated code"
        
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            components = new Container();
        }
        
        #endregion

        #region "Private Methods"

        /// <summary>
        /// The message event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="message">The message.</param>
        /// <param name="handled">The handled.</param>
        private void MessageEvent(object sender, ref Message message, ref bool handled)
        {
            // Handle WM_Hotkey event
            if ((message.Msg != (int) Msgs.WM_HOTKEY) || (message.WParam != (IntPtr) GetType().GetHashCode()))
            {
                return;
            }

            handled = true;
            Debug.WriteLine("HOTKEY pressed!");
            if (Pressed != null)
            {
                Pressed(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Unregister a hotkey.
        /// </summary>
        /// <returns>
        /// Returns true if the hotkey was sucessfully unregistered.
        /// </returns>
        private bool UnregisterHotkey()
        {
            // Unregister hotkey
            return User32.UnregisterHotKey(_window.Handle, GetType().GetHashCode());
        }

        /// <summary>
        /// Register a hotkey.
        /// </summary>
        /// <param name="key">The shortcut key.</param>
        /// <returns>
        /// Returns true if the hotkey was sucessfully registered.
        /// </returns>
        private bool RegisterHotkey(Shortcut key)
        {
            // Register hotkey
            int mod = 0;
            Keys k2 = Keys.None;

            if (((int) key & (int) Keys.Alt) == (int) Keys.Alt)
            {
                mod += (int) Modifiers.MOD_ALT;
                k2 = Keys.Alt;
            }
            
            if (((int) key & (int) Keys.Shift) == (int) Keys.Shift)
            {
                mod += (int) Modifiers.MOD_SHIFT;
                k2 = Keys.Shift;
            }
            
            if (((int) key & (int) Keys.Control) == (int) Keys.Control)
            {
                mod += (int) Modifiers.MOD_CONTROL;
                k2 = Keys.Control;
            }

            Debug.Write(mod + " ");
            Debug.WriteLine((((int) key) - ((int) k2)).ToString());

            return User32.RegisterHotKey(_window.Handle, GetType().GetHashCode(), mod, ((int) key) - ((int) k2));
        }

        #endregion
    }
}